package top.rish.converter.core.info;

import top.rish.converter.core.utils.ObjKit;
import top.rish.converter.core.utils.RefKit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

public class MetaMap extends HashMap<String, Object> {

    public static MetaMap of(Object...objects){
        assert objects!=null && objects.length>0;
        assert objects.length % 2 == 0;
        assert Arrays.stream(objects).allMatch(Objects::nonNull);
        MetaMap mateMap = new MetaMap();
        for (int i = 0; i < objects.length ; i+=2) {
            Object k =  objects[i];
            Object v =  objects[i+1];
           assert k instanceof String;
           mateMap.put((String)k,v);
        }
        return mateMap;
    }

    public static MetaMap ofAnnotation(Annotation annotation) {
        MetaMap mm = new MetaMap();
        Class<? extends Annotation> at = annotation.annotationType();


        Set<Field> fields = RefKit.getAllFields(at);
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                mm.put(field.getName(),field.get(annotation));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return  mm;
    }

    public static MetaMap ofEntity(Object o) {
        MetaMap mate = new MetaMap();
        Set<Field> fields = RefKit.getAllFields(o);
        for (Field field : fields) {
            mate.set(field.getName(),RefKit.getFieldValue(o,field));
        }
        return mate;
    }

    public MetaMap set(String k, Object v){
        super.put(k,v);
        return  this;
    }

    @SafeVarargs
    private final <T> T getNumber(String k,
                                  ObjKit.AnyNumFunc<Object, Boolean> valid,
                                  ObjKit.AnyNumFunc<String, T> parse, T... df){
        Object v =super.get(k);
        if (valid.execute(v)) {
            return parse.execute(Objects.toString(v));
        }
        if(df==null || df.length == 0 || df[0]==null){
            return null;
        }
        return  df[0];
    }

    public  Integer getInt(String k,Integer... df){
        return  this.getNumber(k, ObjKit::isInt,Integer::parseInt,df);
    }

    public  String getStr(String k,String... df){
        return this.getNumber(k, ObjKit::isStr,String::toString,df);
    }

    public  Long getLong(String k,Long... df){
        return  this.getNumber(k, ObjKit::isLong,Long::parseLong,df);
    }

    public  Double getDouble(String k,Double... df){
        return  this.getNumber(k, ObjKit::isDouble,Double::parseDouble,df);
    }

    public MetaMap getMateMap(String k){
        Object v = super.get(k);
        if(v instanceof MetaMap){
            return (MetaMap) v;
        }
        return null;
    }

    public MetaMap put(String k, Object v){
        super.put(k,v);
        return  this;
    }
}
